package com.cardone.common.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import com.cardone.common.dto.ReturnDataDto;
import com.cardone.common.function.ReadDictionaryValueByTypeCodeAndCodeFunction;
import com.cardone.context.ContextHolder;
import com.cardone.context.DictionaryException;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;

/**
 * 返回数据
 *
 * @author yaohaitao
 *
 */
public class ReturnDataUtils {
	/**
	 * 数据转换参数
	 */
	private static Table<String, String, Object> parameters;

	static {
		ReturnDataUtils.parameters = HashBasedTable.create();

		ReturnDataUtils.parameters.put("name", "code", StringUtils.EMPTY);
		ReturnDataUtils.parameters.put("name", "data", StringUtils.EMPTY);
		ReturnDataUtils.parameters.put("name", "message", StringUtils.EMPTY);
	}

	/**
	 * 数据转换参数
	 *
	 * @return
	 */
	public static Table<String, String, Object> getParameters() {
		return HashBasedTable.create(ReturnDataUtils.parameters);
	}

	/**
	 * 生成
	 *
	 * @return 返回数据
	 */
	public static <T> Map<String, Object> newMap() {
		final ReturnDataDto<T> returnData = ReturnDataUtils.newReturnData();

		final Map<String, Object> target = Maps.newHashMap();

		BeanUtils.copyProperties(returnData, target, ReturnDataUtils.parameters);

		return target;
	}

	/**
	 * 生成
	 *
	 * @param returnData
	 *          返回数据
	 * @return 返回数据
	 */
	public static <T> Map<String, Object> newMap(final ReturnDataDto<T> returnData) {
		ReturnDataUtils.newReturnData(returnData);

		final Map<String, Object> target = Maps.newHashMap();

		BeanUtils.copyProperties(returnData, target, ReturnDataUtils.parameters);

		return target;
	}

	/**
	 * 生成
	 *
	 * @param returnData
	 *          返回数据
	 * @param e
	 *          异常
	 * @param log
	 *          日志
	 * @return 返回数据
	 */
	public static <T> Map<String, Object> newMap(final ReturnDataDto<T> returnData, final Exception e, final Logger log) {
		ReturnDataUtils.newReturnData(returnData, e, log);

		final Map<String, Object> target = Maps.newHashMap();

		BeanUtils.copyProperties(returnData, target, ReturnDataUtils.parameters);

		return target;
	}

	/**
	 * 生成
	 *
	 * @param data
	 *          数据
	 * @return 返回数据
	 */
	public static <T> Map<String, Object> newMap(final T data) {
		final ReturnDataDto<T> returnData = ReturnDataUtils.newReturnData(data);

		final Map<String, Object> target = Maps.newHashMap();

		BeanUtils.copyProperties(returnData, target, ReturnDataUtils.parameters);

		return target;
	}

	/**
	 * 生成
	 *
	 * @param data
	 *          数据
	 *
	 * @param e
	 *          异常
	 * @param log
	 *          日志
	 * @return 返回数据
	 */
	public static <T> Map<String, Object> newMap(final T data, final Exception e, final Logger log) {
		final ReturnDataDto<T> returnData = ReturnDataUtils.newReturnData(data, e, log);

		final Map<String, Object> target = Maps.newHashMap();

		BeanUtils.copyProperties(returnData, target, ReturnDataUtils.parameters);

		return target;
	}

	/**
	 * 生成
	 *
	 * @return 返回数据
	 */
	public static <T> ReturnDataDto<T> newReturnData() {
		final ReturnDataDto<T> returnData = ReturnDataDto.newReturnData();

		return ReturnDataUtils.newReturnData(returnData);
	}

	/**
	 * 生成
	 *
	 * @param e
	 *          异常
	 * @param log
	 *          日志
	 * @return 返回数据
	 */
	public static <T> ReturnDataDto<T> newReturnData(final Exception e, final Logger log) {
		final ReturnDataDto<T> returnData = ReturnDataDto.newReturnData();

		return ReturnDataUtils.newReturnData(returnData, e, log);
	}

	/**
	 * 生成
	 *
	 * @param returnData
	 *          返回数据
	 * @return 返回数据
	 */
	public static <T> ReturnDataDto<T> newReturnData(final ReturnDataDto<T> returnData) {
		if (StringUtils.isBlank(returnData.getTypeCode())) {
			if (StringUtils.isBlank(returnData.getMessage()) && "0".equals(returnData.getCode())) {
				returnData.setMessage("提交成功");
			}

			return returnData;
		}

		final ReadDictionaryValueByTypeCodeAndCodeFunction readDictionaryValueByTypeCodeAndCodeFunction = ContextHolder.getBean(ReadDictionaryValueByTypeCodeAndCodeFunction.class);

		if (readDictionaryValueByTypeCodeAndCodeFunction == null) {
			return returnData;
		}

		final String message = readDictionaryValueByTypeCodeAndCodeFunction.execution(returnData.getMessage(), returnData.getTypeCode(), returnData.getCode());

		returnData.setMessage(message);

		return returnData;
	}

	/**
	 * 生成
	 *
	 * @param returnData
	 *          返回数据
	 * @param e
	 *          异常
	 * @param log
	 *          日志
	 * @return 返回数据
	 */
	public static <T> ReturnDataDto<T> newReturnData(final ReturnDataDto<T> returnData, final Exception e, final Logger log) {
		returnData.setMessage(e.getMessage());

		if (StringUtils.isBlank(returnData.getMessage())) {
			final Writer writer = new StringWriter();

			final PrintWriter printWriter = new PrintWriter(writer);

			e.printStackTrace(printWriter);

			returnData.setMessage(writer.toString());
		}

		returnData.setTypeCode(StringUtils.EMPTY);
		returnData.setCode(StringUtils.EMPTY);

		if (e instanceof DictionaryException) {
			final DictionaryException cardOneException = (DictionaryException) e;

			returnData.setTypeCode(cardOneException.getTypeCode());

			returnData.setCode(cardOneException.getCode());
		}

		if (StringUtils.isBlank(returnData.getCode())) {
			returnData.setCode(1);
		}

		log.debug(e.getMessage(), e);

		return ReturnDataUtils.newReturnData(returnData);
	}

	/**
	 * 生成
	 *
	 * @param data
	 *          数据
	 * @return 返回数据
	 */
	public static <T> ReturnDataDto<T> newReturnData(final T data) {
		final ReturnDataDto<T> returnData = ReturnDataDto.newReturnData();

		returnData.setData(data);

		return ReturnDataUtils.newReturnData(returnData);
	}

	/**
	 * 生成
	 *
	 * @param data
	 *          数据
	 *
	 * @param e
	 *          异常
	 * @param log
	 *          日志
	 * @return 返回数据
	 */
	public static <T> ReturnDataDto<T> newReturnData(final T data, final Exception e, final Logger log) {
		final ReturnDataDto<T> returnData = ReturnDataDto.newReturnData();

		returnData.setData(data);

		return ReturnDataUtils.newReturnData(returnData, e, log);
	}
}
